package spu

import (
	"context"
	"github.com/zeromicro/go-zero/core/logx"
	tools "mall/common/utils"
	constans "mall/services/product/rpc/consts"
	"mall/services/product/rpc/internal/domain/bo"
	"mall/services/product/rpc/internal/domain/do"
	"mall/services/product/rpc/internal/mapper"
	"mall/services/product/rpc/internal/mapper/entity"
	"mall/services/product/rpc/internal/svc"
	"mall/services/product/rpc/pb"
)

type QueryListPageLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewQueryListPageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryListPageLogic {
	return &QueryListPageLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *QueryListPageLogic) QueryListPage(in *pb.QuerySpuListPageDTO) (*pb.QuerySpuListPageVO, error) {
	// 1.select count
	spuMapper, spuBO, selectCountCtx, err := l.selectCount(in)
	if err != nil {
		return nil, err
	}
	// 1.1 if select count <= 0 return empty list
	if selectCountCtx <= 0 {
		return &pb.QuerySpuListPageVO{PageSize: in.PageSize, CurrentPage: in.PageNum}, nil
	}
	// 2.select page list
	selectPageList, err := l.selectSpuPageList(in, spuBO, spuMapper)
	if err != nil {
		return nil, err
	}
	// 3.select spu stock
	spuStockMap, err2 := l.selectSpuStock(selectPageList)
	if err2 != nil {
		return nil, err2
	}
	// 4.return obj...
	return l.returnPackage(in.PageNum, in.PageSize, selectCountCtx, selectPageList, spuStockMap), nil
}

func (l *QueryListPageLogic) selectCount(in *pb.QuerySpuListPageDTO) (*mapper.SpuMapper[entity.SpuEntity], bo.SpuBO, int64, error) {
	spuMapper := mapper.NewSpuMapper[entity.SpuEntity]()
	spuBO := bo.SpuBO{}
	spuBO.SpuId = in.SpuId
	spuBO.BrandId = in.BrandId
	spuBO.CategoryId = in.CategoryId
	spuBO.NameAllLike = in.Name
	spuBO.Status = int64(in.Status)
	spuBO.ShopId = in.ShopId
	spuBO.StartTime = in.StartTime
	spuBO.EndTime = in.EndTime
	spuBO.NeStatus = constans.SpuTakeDown
	selectCountCtx, err := spuMapper.SelectCountCtx(l.ctx, l.svcCtx.DBEngin, spuBO)
	return spuMapper, spuBO, selectCountCtx, err
}

func (l *QueryListPageLogic) selectSpuPageList(in *pb.QuerySpuListPageDTO, spuBO bo.SpuBO,
	spuMapper *mapper.SpuMapper[entity.SpuEntity]) ([]entity.SpuEntity, error) {

	pageNum := in.PageNum
	pageSize := in.PageSize
	startPageIndex := 0
	if pageNum > 1 {
		startPageIndex = int((pageNum - 1) * pageSize)
	}
	spuBO.StartIndex = startPageIndex
	spuBO.PageSize = int(pageSize)
	sorts := in.Sorts
	var sortBOArr []bo.OrderBO
	if len(sorts) > 0 {
		for _, v := range sorts {
			orderBO := bo.OrderBO{}
			orderBO.FiledName = tools.ToSnakeCase(v.FiledName)
			if v.Sort == 1 {
				orderBO.Sort = "asc"
			} else {
				orderBO.Sort = "desc"
			}
			sortBOArr = append(sortBOArr, orderBO)
		}
	} else {
		// default sorts
		orderBO := bo.OrderBO{}
		orderBO.FiledName = "update_time"
		orderBO.Sort = "desc"
		sortBOArr = append(sortBOArr, orderBO)
		sortBOArr = append(sortBOArr, bo.OrderBO{
			FiledName: "create_time",
			Sort:      "desc",
		})
	}
	spuBO.Sorts = sortBOArr
	// 3.select spu db
	return spuMapper.SelectPageListCtx(l.ctx, l.svcCtx.DBEngin, spuBO)
}

func (l *QueryListPageLogic) selectSpuStock(selectPageList []entity.SpuEntity) (map[int64]do.SpuStockDO, error) {
	skuMapper := mapper.NewSkuMapper()
	spuIdMap := make(map[int64]bool)
	for _, v := range selectPageList {
		spuIdMap[v.SpuId] = true
	}
	var skuIdArr []int64
	for k := range spuIdMap {
		skuIdArr = append(skuIdArr, k)
	}
	spuStockDOArr, err := skuMapper.CountSpuStockCtx(l.ctx, l.svcCtx.DBEngin, skuIdArr)
	if err != nil {
		return nil, err
	}
	spuStockMap := make(map[int64]do.SpuStockDO)
	for _, v := range spuStockDOArr {
		spuStockMap[v.SpuId] = v
	}
	return spuStockMap, nil
}

func (l *QueryListPageLogic) returnPackage(pageNum int32, pageSize int32, selectCountCtx int64, selectPageList []entity.SpuEntity,
	spuStockMap map[int64]do.SpuStockDO) *pb.QuerySpuListPageVO {
	pageUtil := tools.NewPageUtil[entity.SpuEntity](pageNum, pageSize, int32(selectCountCtx), selectPageList)
	resp := &pb.QuerySpuListPageVO{}
	resp.TotalPage = pageUtil.TotalPage
	resp.HasNextPage = pageUtil.HasNextPage
	resp.CurrentPage = pageUtil.CurrentPage
	resp.TotalCount = pageUtil.TotalCount
	resp.Prev = pageUtil.Prev
	resp.PageSize = pageSize
	resp.Next = pageUtil.Next
	records := pageUtil.Records
	var respRecords []*pb.SpuListInfoVO
	for _, v := range records {
		record := &pb.SpuListInfoVO{}
		stockDO := spuStockMap[v.SpuId]
		if stockDO.SpuId > 0 {
			record.TotalStock = stockDO.ActualStock
			record.ActualStock = stockDO.Stock
		}
		record.SpuId = v.SpuId
		record.BrandId = v.BrandId
		record.CategoryId = v.CategoryId
		record.ShopCategoryId = v.ShopCategoryId
		record.ShopId = v.ShopId
		record.Name = v.Name
		record.SellingPoint = v.SellingPoint
		record.MainImgUrl = v.MainImgUrl
		record.ImgUrls = v.ImgUrls
		record.PriceFee = v.PriceFee
		record.MarketPriceFee = v.MarketPriceFee
		record.Status = int32(v.Status)
		record.HasSkuImg = int32(v.HasSkuImg)
		record.Seq = int32(v.Seq)
		record.BrandName = v.BrandName
		record.CategoryName = v.CategoryName
		record.ShopCategoryName = v.ShopCategoryName
		record.ShopName = v.ShopName
		record.CreateTime = v.CreateTime.Format("2006-01-02 15:04:05")
		record.UpdateTime = v.UpdateTime.Format("2006-01-02 15:04:05")
		respRecords = append(respRecords, record)
	}
	resp.Records = respRecords
	return resp
}
